﻿SSVC.Wrap.Dojo.SetObject("SSVC.SVG.ActiveElement", function()
{

	function reorderElements(sortingElementsArr)
	{
		for (var i in sortingElementsArr)
		{
			if (i === 0)
				sortingElementsArr[i].toBack();
			else
				sortingElementsArr[i].toFront();
		}
	}

	SSVC.Wrap.Dojo.Declare("ActiveElement", SSVC.SVG.Group,
	{
		Contour: null,
		InnerElement: null,
		Frame: null,
		SelectMode: null,
		SelectOptions:
		{
			None: "none",
			Selected: "selected",
			Contoured: "contoured"
		},
		Tops: null,
		InnerXml: "",
		MinSize: 5,

		selectedTop: null,
		selectedPoint: null,

		constructor: function()
		{
			this.Tops = [];
			this._addInnerElement();
			this._addSelection();
			this._arrangeGroupNode();

			this.SelectMode = this.SelectOptions.None;

			SSVC.Wrap.Dojo.On(this.Node, "mousedown", SSVC.Wrap.Dojo.Partial(this.OnMouseDown, this));
			SSVC.Wrap.Dojo.On(this.Node, "dblclick", SSVC.Wrap.Dojo.Partial(this.OnMouseDblClick, this));

			SSVC.Wrap.Dojo.On(this.Node, "mouseover", SSVC.Wrap.Dojo.Partial(this.OnMouseOver, this));
			SSVC.Wrap.Dojo.On(this.Node, "mouseup", SSVC.Wrap.Dojo.Partial(this.OnMouseUp, this));
		},

		OnMouseDblClick: function(callElement) { },

		OnMouseUp: function(callElement)
		{
			callElement.Select();
		},

		OnTopMouseUp: function(callElement)
		{
			callElement.selectedTop = null;
		},

		OnTopMouseDown: function(callElement)
		{
			callElement.selectedTop = arguments[1];
		},

		OnMouseDown: function(callElement)
		{
			var offsetX = arguments[1].offsetX === undefined ? arguments[1].layerX : arguments[1].offsetX;
			var offsetY = arguments[1].offsetY === undefined ? arguments[1].layerY : arguments[1].offsetY;
			callElement.selectedPoint = { x: offsetX, y: offsetY };

		},

		_arrangeInnerElements: function()
		{
			this.InnerElement.update(this.X, this.Y, this.OX, this.OY);
			if (this.Contour != null)
				this.Contour.update(this.X, this.Y, this.OX, this.OY);
			reorderElements([this.InnerElement, this.Frame].concat(this.Tops));
		},

		_addInnerElement: function()
		{
			this.InnerElement = new SSVC.SVG.Rectangle();
		},

		_arrangeGroupNode: function()
		{
			this.addChild(this.Frame);
			this.addChild(this.InnerElement);
			if (this.Contour != null)
				this.addChild(this.Contour);
		},

		_addSelection: function()
		{
			this._addSelectionTops();
			this.Frame = new SSVC.SVG.Rectangle();
			this.Frame.Class = "Frame";

			if (this.Contour == null)
			{
				this.Contour = SSVC.SVG.Shape.Clone(this.InnerElement);
				this.Contour.Class = "Contour";
				this.Contour.ID += "_Contour";
			}
		},

		_addSelectionTops: function()
		{
			for (var el in SSVC.SVG.ActiveElement.Enums.ResizingTops)
			{
				var top = new SSVC.SVG.Circle();
				top.Class = "Top";
				top.Name = el;
				top.Number = SSVC.SVG.ActiveElement.Enums.ResizingTops[el];

				SSVC.Wrap.Dojo.On(top.Node, "mousedown", SSVC.Wrap.Dojo.Partial(this.OnTopMouseDown, this, top.Number));
				SSVC.Wrap.Dojo.On(top.Node, "mouseup", SSVC.Wrap.Dojo.Partial(this.OnTopMouseUp, this));

				this.Tops.push(top);
				this.Node.appendChild(top.Node);
			}
			this._setCursorAttrForTops();
		},

		_setCursorAttrForTops: function()
		{
			this.Tops[0].Node.setAttribute("cursor", "nw-resize");
			this.Tops[1].Node.setAttribute("cursor", "w-resize");
			this.Tops[2].Node.setAttribute("cursor", "sw-resize");
			this.Tops[3].Node.setAttribute("cursor", "ne-resize");
			this.Tops[4].Node.setAttribute("cursor", "e-resize");
			this.Tops[5].Node.setAttribute("cursor", "se-resize");
			this.Tops[6].Node.setAttribute("cursor", "n-resize");
			this.Tops[7].Node.setAttribute("cursor", "s-resize");
		},

		_arrangeTops: function()
		{
			//todo: temporary cap
			var topRadius = SSVC.SVG.Shape.GetProperty("top");
			topRadius = 3;

			this.Tops[0].update(this.Frame.X, this.Frame.Y, topRadius);
			this.Tops[1].update(this.Frame.X, this.Frame.Y + this.Frame.OY / 2, topRadius);
			this.Tops[2].update(this.Frame.X, this.Frame.Y + this.Frame.OY, topRadius);
			this.Tops[3].update(this.Frame.X + this.Frame.OX, this.Frame.Y, topRadius);
			this.Tops[4].update(this.Frame.X + this.Frame.OX, this.Frame.Y + this.Frame.OY / 2, topRadius);
			this.Tops[5].update(this.Frame.X + this.Frame.OX, this.Frame.Y + this.Frame.OY, topRadius);
			this.Tops[6].update(this.Frame.X + this.Frame.OX / 2, this.Frame.Y, topRadius);
			this.Tops[7].update(this.Frame.X + this.Frame.OX / 2, this.Frame.Y + this.Frame.OY, topRadius);
		},

		_showContour: function()
		{
			this.Contour.Visible = true;
		},

		_hideContour: function()
		{
			this.Contour.Visible = false;
		},

		_showTops: function()
		{
			this._arrangeTops();
			for (var el in this.Tops)
			{
				this.Tops[el].Visible = true;
			}
		},

		_hideTops: function()
		{
			for (var el in this.Tops)
			{
				this.Tops[el].Visible = false;
			}
		},

		_showSelection: function()
		{
			this.Frame.Transparent = false;
			this._showTops();
		},

		_hideSelection: function()
		{
			this.Frame.Transparent = true;
			this._hideTops();
		},

		_showInnerElement: function()
		{
			this.InnerElement.Visible = true;
			this._setInnerXml();
		},

		_hideInnerElement: function()
		{
			this.InnerElement.Visible = false;
		},

		_refreshSelection: function()
		{
			var lineWidth = (this.InnerElement.LineWidth) ? this.InnerElement.LineWidth : 2;
			this.Frame.update(this.X - lineWidth, this.Y - lineWidth, this.OX + lineWidth * 2, this.OY + lineWidth * 2);
			switch (this.SelectMode)
			{
				case this.SelectOptions.Contoured:
					this._showContour();
					this._hideInnerElement();
					this._hideSelection();
					break;
				case this.SelectOptions.Selected:
					this._showSelection();
					this._showInnerElement();
					this._hideContour();
					break;
				case this.SelectOptions.None:
					this._hideContour();
					this._hideSelection();
					this._showInnerElement();
					break;
			}
		},

		_move: function(x, y, selectedPoint)
		{
			if (!this.selectedPoint) return;

			var deltaX = x - this.selectedPoint.x;
			var deltaY = y - this.selectedPoint.y;

			this.selectedPoint.x = x;
			this.selectedPoint.y = y;

			this.X += deltaX;
			this.Y += deltaY;

			this.SelectMode = this.SelectOptions.Contoured;
		},

		_resize: function(x, y, shiftKey)
		{
			function setValuesForLeft()
			{
				var currX = newx;
				newx = x;
				var diff = currX - x;
				if (shiftKey)
					diff = diff * 2;
				newox += diff;
			}
			function setValuesForRight()
			{
				var currX = newx + newox;
				var diff = currX - x;
				if (shiftKey)
				{
					newx += diff;
					diff = diff * 2;
				}
				newox -= diff;
			}
			function setValuesForTop()
			{
				var currY = newy;
				newy = y;
				var diff = currY - y;
				if (shiftKey)
					diff = diff * 2;
				newoy += diff;
			}
			function setValuesForBottom()
			{
				var currY = newy + newoy;
				var diff = currY - y;
				if (shiftKey)
				{
					newy += diff;
					diff = diff * 2;
				}
				newoy -= diff;
			}

			if (!this.selectedTop) return;

			var newx = this.X,
                newy = this.Y,
                newox = this.OX,
                newoy = this.OY;
			switch (this.selectedTop)
			{
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.LEFT:
					setValuesForLeft();
					break;
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.RIGHT:
					setValuesForRight();
					break;
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.TOP:
					setValuesForTop();
					break;
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.BOTTOM:
					setValuesForBottom();
					break;
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.LEFT_TOP:
					setValuesForLeft();
					setValuesForTop();
					break;
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.LEFT_BOTTOM:
					setValuesForLeft();
					setValuesForBottom();
					break;
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.RIGHT_TOP:
					setValuesForRight();
					setValuesForTop();
					break;
				case SSVC.SVG.ActiveElement.Enums.ResizingSides.RIGHT_BOTTOM:
					setValuesForRight();
					setValuesForBottom();
					break;
			}

			if (newox <= this.MinSize || newoy <= this.MinSize) return;
			this.update(newx, newy, newox, newoy);
		},

		_getTopByNumber: function(number)
		{
			for (var i in this.Tops)
			{
				if (this.Tops[i].Number == number)
					return this.Tops[i];
			}
			return null;
		},

		_getRectSpace: function(startX, startY, currX, currY)
		{
			var ox = currX - startX;
			var oy = currY - startY;
			var x, y, side;

			if (ox < 0 && oy < 0)
			{
				ox = Math.abs(ox);
				oy = Math.abs(oy);
				x = startX - ox;
				y = startY - oy;
				side = 3;
			}
			else if (ox < 0 && oy >= 0)
			{
				ox = Math.abs(ox);
				x = startX - ox;
				y = startY;
				side = 4;
			}
			else if (ox >= 0 && oy < 0)
			{
				oy = Math.abs(oy);
				x = startX;
				y = startY - oy;
				side = 2;
			}
			else
			{
				x = startX;
				y = startY;
				side = 1;
			}

			return { x: x, y: y, ox: ox, oy: oy, side: side };
		},

		_setInnerXml: function()
		{
			this.InnerXml = this.InnerElement.getXml().xml;
		},

		toFront: function()
		{
			this.Node.ownerSVGElement.appendChild(this.Node);
		},

		toBack: function()
		{
			this.Node.ownerSVGElement.appendChild(this.Node, this.Node.ownerSVGElement.firstChild);
		},

		GetOuterXml: function()
		{
			return this.InnerElement.getXml();
		},

		restoreCoo: function(xmlNode) // override for any shape
		{
			this.X = +xmlNode.getAttribute(this.InnerElement.axis.x);
			this.Y = +xmlNode.getAttribute(this.InnerElement.axis.y);
			this.OX = +xmlNode.getAttribute(this.InnerElement.axis.ox);
			this.OY = +xmlNode.getAttribute(this.InnerElement.axis.oy);
		},

		SetXml: function(xmldoc)
		{
			this.InnerElement.applyXml(xmldoc);
			this.restoreCoo(xmldoc);
			this.SelectMode = this.SelectOptions.None;
			this.Refresh();
		},

		Fill: function(rgb)
		{
			this.InnerElement.Background = rgb;
		},

		SetLineProperties: function(width, color, dash)
		{
			this.InnerElement.LineColor = color;
			this.InnerElement.LineDash = dash;
			this.InnerElement.LineWidth = width;
		},

		AddProperties: function(properties)
		{
			this.FontSize = (properties.fontSize) ? properties.fontSize : "";
			if (properties.strokeWidth)
				this.SetLineProperties(properties.strokeWidth, properties.lineColor, properties.strokeDash);
			if (properties.background)
				this.Fill(properties.background);
		},

		Refresh: function()
		{
			this.update(this.X, this.Y, this.OX, this.OY);
			this._arrangeInnerElements();
			this._refreshSelection();
		},

		Move: function(x, y, shiftKey)
		{
			if (this.selectedTop == null)
			{
				this._move(x, y);
			}
			else
			{
				this._resize(x, y, shiftKey);
			}
			this.Refresh();
		},

		Draw: function(startX, startY, currX, currY, shiftKey)
		{
			this.SelectMode = this.SelectOptions.Contoured;

			var rectCoordinates = this._getRectSpace(startX, startY, currX, currY);
			if (shiftKey)
			{
				if (rectCoordinates.ox > rectCoordinates.oy)
					rectCoordinates.oy = rectCoordinates.ox;
				else
					rectCoordinates.ox = rectCoordinates.oy;
			}

			this.X = rectCoordinates.x; this.Y = rectCoordinates.y; this.OX = rectCoordinates.ox; this.OY = rectCoordinates.oy;
			this.Refresh();
		},

		Select: function()
		{
			this.SelectMode = this.SelectOptions.Selected;
			this.Refresh();
		},

		Deselect: function()
		{
			this.SelectMode = this.SelectOptions.None;
			this.Cursor = SSVC.SVG.ActiveElement.Enums.Cursors.Default;
			this.Refresh();
		},

		ScaleX: function(factor)
		{
			if (factor <= 0)
				return;

			this.X *= factor;
			this.OX *= factor;
			this.Refresh();
		},

		ScaleY: function(factor)
		{
			if (factor <= 0)
				return;

			this.Y *= factor;
			this.OY *= factor;
			this.Refresh();
		},

		Delete: function()
		{
			this.Node.parentNode.removeChild(this.Node);
		}
	});

	ActiveElement.XmlDeserialize = function(xmlDoc)
	{
		var obj = SSVC.SVG.ActiveElement.CreateElementByTag(xmlDoc.nodeName, xmlDoc.getAttribute("complextype"));
		obj.SetXml(xmlDoc);
		//obj.Refresh();
		return obj;
	};

	ActiveElement.CreateElementByTag = function(tagName, complextype)
	{
		switch (tagName)
		{
			case SSVC.SVG.ActiveElement.Enums.ElementType.ELLIPSE:
				return new SSVC.SVG.ActiveEllipseElement();
			case SSVC.SVG.ActiveElement.Enums.ElementType.LINE:
				return new SSVC.SVG.ActiveLineElement();
			case SSVC.SVG.ActiveElement.Enums.ElementType.SCRIBBLE:
				return new SSVC.SVG.ActiveScribbleElement();
			case SSVC.SVG.ActiveElement.Enums.ElementType.COMPLEX:
				if (complextype == SSVC.SVG.ActiveElement.Enums.ElementType.LABEL)
					return new SSVC.SVG.ActiveLabelElement();
				break;
			default:
				return new SSVC.SVG.ActiveElement();
		}
	};

	ActiveElement.Enums =
{
	// Selected area tops:
	//  1........7........4
	//  .                 .
	//  .                 .
	//  2                 5
	//  .                 .
	//  .                 .
	//  3........8........6  

	ResizingSides:
    {
    	LEFT: +2,
    	RIGHT: +5,
    	TOP: +7,
    	BOTTOM: +8,
    	LEFT_TOP: +1,
    	RIGHT_TOP: +4,
    	LEFT_BOTTOM: +3,
    	RIGHT_BOTTOM: +6
    },

	ElementType:
    {
    	ELLIPSE: "ellipse",
    	RECT: "rect",
    	LINE: "line",
    	LABEL: "label",
    	SCRIBBLE: "polyline",
    	COMPLEX: "g"
    },
	ElementAxis:
    {
    	ForLine: { x: "x1", y: "y1", ox: "x2", oy: "y2" },
    	ForRectangle: { x: "x", y: "y", ox: "width", oy: "height" },
    	ForEllipse: { x: "cx", y: "cy", ox: "rx", oy: "ry" },
    	ForCircle: { x: "cx", y: "cy", ox: "r", oy: "r" },
    	ForText: { x: "x", y: "y", ox: "width", oy: "height" },
    	ForMarker: { x: "refX", y: "refY", ox: "markerWidth", oy: "markerHeight" }
    },
	ResizingTops:
    {
    	TopLeft: 1,
    	MiddleLeft: 2,
    	BottomLeft: 3,
    	TopRight: 4,
    	MiddleRight: 5,
    	BottomRight: 6,
    	TopMiddle: 7,
    	BottomMiddle: 8,
    },

	SelectMode:
        {
        	None: 0, Selected: 1, Contoured: 2
        },
	Cursors:
        {
        	Move: "move",
        	Default: "default"
        }
};

	return ActiveElement;
}());
